package com.star.mp3ToPCM;

import java.io.*;

public class FFmpegConverter {
    
    private static final float TARGET_SAMPLE_RATE = 16000.0f;
    private static final int TARGET_SAMPLE_SIZE = 16;
    private static final int TARGET_CHANNELS = 1;
    
    /**
     * 使用FFmpeg将MP3文件转换为PCM音频流
     * @param mp3FilePath MP3文件路径
     * @param pcmOutputStream PCM输出流
     * @throws Exception 转换异常
     */
    public static void convert(String mp3FilePath, OutputStream pcmOutputStream) throws Exception {
        File mp3File = new File(mp3FilePath);
        if (!mp3File.exists() || !mp3File.isFile()) {
            throw new FileNotFoundException("MP3文件不存在: " + mp3FilePath);
        }
        
        System.out.println("开始使用FFmpeg转换文件: " + mp3FilePath);
        
        // 检查FFmpeg是否可用
        if (!isFFmpegAvailable()) {
            throw new RuntimeException("FFmpeg未安装或不可用，请先安装FFmpeg");
        }
        
        // 构建FFmpeg命令
        // ffmpeg -i input.mp3 -f s16le -ar 16000 -ac 1 output.pcm
        ProcessBuilder processBuilder = new ProcessBuilder(
            "ffmpeg",
            "-i", mp3FilePath,
            "-f", "s16le",           // PCM 16位小端序格式
            "-ar", "16000",          // 采样率16000Hz
            "-ac", "1",              // 单声道
            "-"
        );
        
        System.out.println("执行命令: " + String.join(" ", processBuilder.command()));
        
        // 启动FFmpeg进程
        Process process = processBuilder.start();
        
        // 获取FFmpeg的输出流（PCM数据）
        InputStream ffmpegOutput = process.getInputStream();
        InputStream ffmpegError = process.getErrorStream();
        
        // 创建错误输出线程
        Thread errorThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(ffmpegError))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.err.println("[FFmpeg] " + line);
                }
            } catch (IOException e) {
                System.err.println("读取FFmpeg错误输出时出错: " + e.getMessage());
            }
        });
        errorThread.start();
        
        // 复制PCM数据到输出流
        copyPCMData(ffmpegOutput, pcmOutputStream);
        
        // 等待进程完成
        int exitCode = process.waitFor();
        errorThread.join();
        
        if (exitCode != 0) {
            throw new RuntimeException("FFmpeg转换失败，退出码: " + exitCode);
        }
        
        System.out.println("FFmpeg转换完成!");
    }
    
    /**
     * 检查FFmpeg是否可用
     */
    private static boolean isFFmpegAvailable() {
        try {
            Process process = new ProcessBuilder("ffmpeg", "-version").start();
            int exitCode = process.waitFor();
            return exitCode == 0;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 复制PCM数据
     */
    private static void copyPCMData(InputStream source, OutputStream target) throws IOException {
        byte[] buffer = new byte[8192];
        int bytesRead;
        long totalBytes = 0;
        
        System.out.println("开始复制PCM数据...");
        
        while ((bytesRead = source.read(buffer)) != -1) {
            if (bytesRead > 0) {
                target.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
                
                // 每处理1MB打印一次进度
                if (totalBytes % (1024 * 1024) == 0) {
                    System.out.println("已处理: " + (totalBytes / (1024 * 1024)) + "MB");
                }
            }
        }
        
        target.flush();
        System.out.println("PCM数据复制完成，总字节数: " + totalBytes);
    }
    
    /**
     * 获取目标PCM格式信息
     */
    public static String getTargetFormatDescription() {
        return String.format("16000Hz, 16bit, mono, little-endian PCM");
    }
    
    public static void main(String[] args) {
        String inputMp3Path = "/Users/star/IdeaProjects/java-basic/src/main/resources/mp3/yequ.mp3";
        String outputPcmPath = "/Users/star/IdeaProjects/java-basic/src/main/resources/mp3/output_ffmpeg.pcm";
        
        try (FileOutputStream pcmOutputStream = new FileOutputStream(outputPcmPath)) {
            System.out.println("=== FFmpeg MP3到PCM转换器 ===");
            System.out.println("目标格式: " + getTargetFormatDescription());
            
            // 检查FFmpeg是否可用
            if (!isFFmpegAvailable()) {
                System.err.println("错误: FFmpeg未安装或不可用");
                System.err.println("请先安装FFmpeg:");
                System.err.println("  macOS: brew install ffmpeg");
                System.err.println("  Ubuntu: sudo apt-get install ffmpeg");
                System.err.println("  Windows: 下载并安装FFmpeg，然后将其添加到PATH环境变量");
                return;
            }
            
            long startTime = System.currentTimeMillis();
            
            convert(inputMp3Path, pcmOutputStream);
            
            long endTime = System.currentTimeMillis();
            System.out.println("转换完成! 耗时: " + (endTime - startTime) + "ms");
            System.out.println("PCM文件已保存至: " + outputPcmPath);
        } catch (Exception e) {
            System.err.println("转换失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}